前几天和东盟君讨论关于在 @property(nonatomic,copy)NSString * string;
中 copy
的使用问题. 虽然自己很明白,见到NSString
,果断用 copy
,但是却说不出个道道.
今天偶尔在一片国外论坛的文章上看到了关于这个的内容(因为在pad上看的,具体地址没法引用了).所以简单记录一下.
因为类似 NSString这样的不可变父类,它们有可变的子类(比如 NSMutableString),那么就可能造成修改指针指向的结果,而这是我们不愿意看到的
是比较抽象的描述,要弄明白这段话,需要明确 copy
做了什么 ?
在官方的描述中: copy
是复制一个对象,并强引用它.
那么开始解释一开始的话:
假设我有一个 Person
类,他有一个 name
属性,它是NSString
类型的.不可变对象对吧.
那么问题来了,下面的语法是成立的:
1 | NSMutableString * mutableString = [[NSMutableString alloc]initWithString:@"gg"]; |
上面1处首先语法没有问题, NSString是 NSMutableString的父类.
然后这个时候,如果 name
属性是 @property
是 strong
的,
那么 per.name
和 mutableString
指向的是同一块内存区域,
那么,我就可以通过修改 mutableString
来修改per.name
了,而当初我们既然选择了 NSString
,那么就是考虑到不会对其进行修改的.所以,这样违背了我们的初衷.
如果是copy
,per.name
在使用前会复制一份出来,这样使用的其实是它的副本,即使修改了mutableString
也不会对per.name
的本尊造成影响.
关于 copy 和 mutableCopy
现在我说的这两者是在代码中使用的时候,就是对象创建和赋值时候的.
苹果的设计是:
- copy 拿到的永远是不可变对象
- mutableCopy 拿到的是可变对象
为什么这样设计呢?
以上两者的调用者可能是 可变的或者不可变的,那么就会有四种组合,对于开发者去记忆四种组合是比较蹩脚的.所以干脆
- 不管调用者类型是可变与否,copy到得就不可变
- 不管调用者类型是可变与否,mutableCopy到得就是可变对象
关于创建可变类型
以前都是用类似 NSMutableString * string = [ NSMutableString string ];
这样的方式创建,但是在和东盟君讨论的时候,打印了一下,发现 string
的class是:
1 | NSString * string = [NSString stringWithFormat:@"string"]; |
打印结果:
1 | 2015-05-20 10:36:43.549 TestNsstring[10993:1874316] string is __NSCFString |
究其原因, NSString是一个类簇,具体的实现都会找到合适的类,这个不用纠结了.
不久之后,在 iOS6 by Tutorial中一书中看到关于 [@[] mutableCopy]
和 [@{} mutableCopy]
这样的用法.
也符合 copy 和 mutableCopy 的准则